package ext.acae2.util;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;

import wt.access.NotAuthorizedException;
import wt.iba.definition.DefinitionLoader;
import wt.iba.definition.IBADefinitionException;
import wt.iba.definition.litedefinition.AbstractAttributeDefinizerView;
import wt.iba.definition.litedefinition.AttributeDefDefaultView;
import wt.iba.definition.litedefinition.AttributeDefNodeView;
import wt.iba.definition.litedefinition.BooleanDefView;
import wt.iba.definition.litedefinition.FloatDefView;
import wt.iba.definition.litedefinition.IntegerDefView;
import wt.iba.definition.litedefinition.RatioDefView;
import wt.iba.definition.litedefinition.ReferenceDefView;
import wt.iba.definition.litedefinition.StringDefView;
import wt.iba.definition.litedefinition.TimestampDefView;
import wt.iba.definition.litedefinition.URLDefView;
import wt.iba.definition.litedefinition.UnitDefView;
import wt.iba.definition.service.IBADefinitionHelper;
import wt.iba.value.DefaultAttributeContainer;
import wt.iba.value.IBAHolder;
import wt.iba.value.litevalue.AbstractValueView;
import wt.iba.value.service.IBAValueDBService;
import wt.iba.value.service.IBAValueHelper;
import wt.iba.value.service.LoadValue;
import wt.log4j.LogR;
import wt.session.SessionHelper;
import wt.util.WTException;
import wt.util.WTPropertyVetoException;

public class IBAUtil {

    private Map<String, Object[]> ibaContainer;
    private static final Logger LOGGER = LogR.getLogger(IBAUtil.class.getName());

    public IBAUtil(IBAHolder ibaHolder) throws RemoteException, WTException {
        LOGGER.debug("> Start IBAUtil");
        LOGGER.debug("ibaHolder class: " + ibaHolder.getClass().getName());
        
        ibaContainer = new HashMap<String, Object[]>();
        ibaHolder = IBAValueHelper.service.refreshAttributeContainer(
                ibaHolder, null, SessionHelper.getLocale(), null);
        DefaultAttributeContainer attrContainer 
                = (DefaultAttributeContainer) ibaHolder.getAttributeContainer();
        
        if (attrContainer == null) {
            LOGGER.error("attributeContainer is null!");
            return;
        }
        
        AttributeDefDefaultView[] definitionViews = attrContainer.getAttributeDefinitions();
        for (AttributeDefDefaultView definitionView : definitionViews) {
            AbstractValueView[] valueViews = attrContainer.getAttributeValues(definitionView);
            
            if (valueViews == null) {
                LOGGER.error("valueViews is null!");
                continue;
            }
            
            Object[] nameValue = new Object[2];
            nameValue[0] = definitionView;
            nameValue[1] = valueViews[0];
            ibaContainer.put(definitionView.getName(), nameValue);
        }
        
        LOGGER.debug("> End IBAUtil");
    }

    public String getIBAValue(String ibaName) {
        LOGGER.debug("> Start getIBAValue");
        
        Object[] nameValue = ibaContainer.get(ibaName);
        
        if (nameValue == null) {
            LOGGER.error("nameValue is null");
            return null;
        }
        
        AbstractValueView valueView = (AbstractValueView) nameValue[1];
        
        LOGGER.debug("> End getIBAValue");
        return valueView.getLocalizedDisplayString();
    }
    
    public void setIBAValue(String name, String value) 
            throws WTPropertyVetoException, IBADefinitionException, NotAuthorizedException, RemoteException, WTException {
        LOGGER.debug("> Start setIBAValue");
        LOGGER.debug("name: " + name);
        LOGGER.debug("value: " + value);
        
        AttributeDefDefaultView definitionView = null;
        
        Object[] nameValue = ibaContainer.get(name);
        
        if (nameValue == null) {
            LOGGER.info("nameValue is null");
            
            definitionView = getAttributeDefinition(name);
            
            if (definitionView == null) {
                LOGGER.error("definitionView is null!");
                return;
            }
        }
        else {
            definitionView = (AttributeDefDefaultView) nameValue[0];
        }
        
        AbstractValueView newValueView = internalCreateValue(definitionView, value);
        if (newValueView == null) {
            LOGGER.error("newValueView is null");
            return;
        }
        
        newValueView.setState(AbstractValueView.CHANGED_STATE);
        Object[] newNameValue = new Object[2];
        newNameValue[0] = definitionView;
        newNameValue[1] = newValueView;
        ibaContainer.put(name, newNameValue);
        
        LOGGER.debug("> End setIBAValue");
    }
    
    private AbstractValueView internalCreateValue(AttributeDefDefaultView definitionView, String value) {
        LOGGER.debug("> Start internalCreateValue");
        LOGGER.debug("definitionView class: " + definitionView.getClass().getName());
        
        AbstractValueView valueView = null;
        
        if (definitionView instanceof FloatDefView) {
            valueView = LoadValue.newFloatValue(definitionView, value, null);
        }
        else if (definitionView instanceof StringDefView) {
            valueView = LoadValue.newStringValue(definitionView, value);
        }
        else if (definitionView instanceof IntegerDefView) {
            valueView = LoadValue.newIntegerValue(definitionView, value);
        }
        else if (definitionView instanceof RatioDefView) {
            valueView = LoadValue.newRatioValue(definitionView, value, null);
        }
        else if (definitionView instanceof TimestampDefView) {
            valueView = LoadValue.newTimestampValue(definitionView, value);
        }
        else if (definitionView instanceof BooleanDefView) {
            valueView = LoadValue.newBooleanValue(definitionView, value);
        }
        else if (definitionView instanceof URLDefView) {
            valueView = LoadValue.newURLValue(definitionView, value, null);
        }
        else if (definitionView instanceof ReferenceDefView) {
            valueView = LoadValue.newReferenceValue(definitionView, "ClassificationNode", value);
        }
        else if (definitionView instanceof UnitDefView) {
            valueView = LoadValue.newUnitValue(definitionView, value, null);
        }
        
        LOGGER.debug("> End internalCreateValue");
        return valueView;
    }

    public IBAHolder updateIBAHolder(IBAHolder ibaHolder) throws RemoteException, WTException, WTPropertyVetoException {
        LOGGER.debug("> Start updateIBAHolder");
        LOGGER.debug("ibaHolder class: " + ibaHolder.getClass().getName());
        
        DefaultAttributeContainer attrContainer 
                = (DefaultAttributeContainer) (IBAValueHelper.service.refreshAttributeContainerWithoutConstraints(
                        ibaHolder)).getAttributeContainer();
        
        for (String ibaName : ibaContainer.keySet()) {
            
            Object[] nameValue = ibaContainer.get(ibaName);
            AttributeDefDefaultView definitionView = (AttributeDefDefaultView) nameValue[0];
            AbstractValueView valueView = (AbstractValueView) nameValue[1];
            
            if (valueView.getState() == AbstractValueView.CHANGED_STATE) {
                attrContainer.deleteAttributeValues(definitionView);
                valueView.setState(AbstractValueView.NEW_STATE);
                attrContainer.addAttributeValue(valueView);
            }
        }

        attrContainer.setConstraintParameter("CSM");
        ibaHolder.setAttributeContainer(attrContainer);
        
        LOGGER.debug("> End updateIBAHolder");
        return ibaHolder;
    }

    public IBAHolder saveIBAHolder(IBAHolder ibaHolder) throws WTException, RemoteException, WTPropertyVetoException {
        LOGGER.debug("> Start saveIBAHolder");
        LOGGER.debug("> ibaHolder class: " + ibaHolder.getClass().getName());
        
        ibaHolder = updateIBAHolder(ibaHolder);
        
        DefaultAttributeContainer attrContainer = (DefaultAttributeContainer) ibaHolder.getAttributeContainer();
        IBAValueDBService dbService = new IBAValueDBService();
        attrContainer = (DefaultAttributeContainer) dbService.updateAttributeContainer(
                ibaHolder,attrContainer.getConstraintParameter(), null, null);
        ibaHolder.setAttributeContainer(attrContainer);
        
        LOGGER.debug("> End saveIBAHolder");
        return ibaHolder;
    }
    
    private AttributeDefDefaultView getAttributeDefinition(String attributeName) 
            throws IBADefinitionException, NotAuthorizedException, RemoteException, WTException {
        LOGGER.debug("> Start getAttributeDefinition");
        
        AttributeDefDefaultView definitionView = IBADefinitionHelper.service.getAttributeDefDefaultViewByPath(attributeName);
        
        if (definitionView == null) {
            LOGGER.info("definitionView is null!");
            
            AbstractAttributeDefinizerView definizerView = DefinitionLoader.getAttributeDefinition(attributeName);
            
            if (definizerView == null) {
                LOGGER.error("definizerView is null!");
                return null;
            }
            
            definitionView = IBADefinitionHelper.service.getAttributeDefDefaultView((AttributeDefNodeView) definizerView);
        }
        
        LOGGER.debug("> End getAttributeDefinition");
        return definitionView;
    }
}
